Skip to content

默寫判斷放寬 + 假名書寫系統嚴格化 + 選擇題六向題型 + 詞性顯示#1

Merged
RiceTooCold merged 3 commits into
mainfrom
claude/handwritten-grading-standards-xFlhV
Jun 8, 2026
Merged

默寫判斷放寬 + 假名書寫系統嚴格化 + 選擇題六向題型 + 詞性顯示#1
RiceTooCold merged 3 commits into
mainfrom
claude/handwritten-grading-standards-xFlhV

Conversation

@RiceTooCold

Copy link
Copy Markdown
Owner

概要

調整默寫(手寫題)判斷的嚴謹度、強化選擇題的多元性,並在題目顯示詞性,讓填答更直覺。

一、默寫判斷標準調整(src/lib/text.js, TypingMode.jsx

漢字 ↔ 假名:互通

  • 不再依題目方向硬性區分;漢字形與讀音形任一命中即算對。

括號內容:可有可無

  • surfaceForms 把每個括號段(()[]【】)視為獨立可選,展開「保留/移除」的組合:
    • 質問(する) → 接受 質問、質問する
    • [電話を]かけます(かける) → 接受 かけます、電話をかけます、かける
    • あげます(あげる) → 接受 あげます、あげる
  • 補上原本沒處理的 【】(お) 前綴。

平假名 ↔ 片假名:不互通

  • normalizeAnswer 移除片假名→平假名折疊:かぞくカゾク 不再視為相同,假名作答需用正確書寫系統。
  • 同書寫系統內的長音仍寬鬆(ストーブ = ストブ),全形→半形維持。

二、選擇題擴充為六種題型(QuizMode.jsx

以「意思/漢字/讀音」三面向兩兩組合出題:

題目→選項 適用
意思↔漢字、意思↔讀音 全詞
漢字↔讀音 僅「漢字≠讀音」的詞(純假名詞會退化,故排除)
  • 每種題型有對應提問語(如「這個讀音的漢字是?」)。
  • 防漏答案:讀音為題時,漢字選項與題目皆不顯示讀音。
  • distractor 依答案面實際顯示字串去重,避免同音/同形選項重複。

三、題目顯示詞性

  • 默寫與選擇題題目加上詞性 badge(word.tags[0],沿用 Flashcard 既有 variant="pos" 樣式),無詞性的詞不顯示。

驗證

  • pnpm build 通過(45 modules,無錯誤)。
  • 默寫判斷:17 案手動測試全過(漢字/假名互通、括號可選、平/片假名嚴格、長音寬鬆)。
  • 選擇題生成:8000 次隨機模擬通過所有不變式(每題 4 個相異選項、答案必在選項中、漢字↔讀音題型只落在有獨立讀音的詞、題目與選項文字皆非空)。

未改動任何單字資料,僅調整判斷與顯示邏輯。

https://claude.ai/code/session_01BUW66ehc5s8E1DcXMTuceY


Generated by Claude Code

claude added 3 commits June 8, 2026 01:36
- judge 不再依題目方向硬性區分:漢字形與讀音形任一命中即算對
- surfaceForms 把每個括號段(()[]【】)視為可選,展開保留/移除組合,
  並接受括號內容作為替代形(あげます(あげる)→ 接受 あげる)
- normalizeAnswer 新增 foldKana 選項;片假名外來語(字身全為片假名)
  比對時不折成平假名,逼使以片假名作答
- bareWord 補上 【】 段落處理
- normalizeAnswer 移除片假名→平假名折疊:かぞく 與 カゾク 不再互通,
  假名作答需用正確書寫系統;漢字↔假名仍可(由 surfaceForms 涵蓋)
- 移除不再需要的 isKatakanaWord / foldKana / bareWord
- 默寫與選擇題題目加上詞性 badge(word.tags[0],沿用 Flashcard 慣例)
- 以 (題目面, 答案面) 組合出題:意思↔漢字、意思↔讀音、漢字↔讀音 各兩向
- 漢字↔讀音 僅用於有獨立讀音的詞(純假名詞的漢字=讀音,會退化)
- distractor 依答案面去重,避免同音/同形選項重複
- 渲染防漏答案:讀音為題時漢字選項與題目不顯示讀音
- 8000 次生成模擬通過所有不變式
Copilot AI review requested due to automatic review settings June 8, 2026 01:58
@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tangochou Ready Ready Preview, Comment Jun 8, 2026 1:58am

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the quiz/typing experience to (1) loosen typing-mode correctness rules around kanji vs. reading and bracketed segments, (2) expand multiple-choice quizzes into 6 “prompt→answer side” pairings across meaning/kanji/reading, and (3) display part-of-speech badges on questions when available.

Changes:

  • Introduces surfaceForms() and updates typing-mode judgment to accept either kanji or reading (plus optional bracket segments), while making hiragana/katakana not interchangeable.
  • Refactors QuizMode question generation to randomly select among six prompt/answer-side pairings and dedupe distractors by rendered answer text.
  • Adds POS badge display (word.tags[0]) to TypingMode and QuizMode question headers.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/lib/text.js Adds surfaceForms() and adjusts normalization rules to enforce kana-script strictness.
src/components/TypingMode.jsx Updates answer judging to accept either kanji/reading surface forms and shows POS badge in the prompt UI.
src/components/QuizMode.jsx Expands quiz to 6 prompt/answer pairings, adjusts furigana display rules, and shows POS badge in the prompt UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/text.js
Comment on lines +31 to +50
const parts = [] // { text, optional }
const re = /[([【]([^)]】]*)[)]】]/g
let last = 0
let m
while ((m = re.exec(b))) {
if (m.index > last) parts.push({ text: b.slice(last, m.index), optional: false })
parts.push({ text: m[1], optional: true })
last = re.lastIndex
}
if (last < b.length) parts.push({ text: b.slice(last), optional: false })

let combos = ['']
for (const p of parts) {
combos = p.optional
? combos.flatMap((c) => [c, c + p.text]) // drop or keep this segment
: combos.map((c) => c + p.text)
}
const set = new Set(combos.map(clean))
for (const p of parts) if (p.optional) set.add(clean(p.text)) // standalone alternative
set.delete('')
@RiceTooCold
RiceTooCold merged commit ab85477 into main Jun 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants